/*
 ------------------------------------------------------------------------------
 Copyright (C) 2013 Eternal Games.

 This file is part of the GLQuake source code.

 The GLQuake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The GLQuake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the GLQuake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// r_local.h - local header to all renderer files
//


#ifndef __R_LOCAL_H__
#define __R_LOCAL_H__


#include "../client/client.h"
#include "r_public.h"
#include "qgl.h"


#define GL_INDEX_TYPE					GL_UNSIGNED_INT

#define GL_VERTEX_XYZ(ptr)				((const byte *)(ptr) + 0)
#define GL_VERTEX_NORMAL(ptr)			((const byte *)(ptr) + 12)
#define GL_VERTEX_TANGENT1(ptr)			((const byte *)(ptr) + 24)
#define GL_VERTEX_TANGENT2(ptr)			((const byte *)(ptr) + 36)
#define GL_VERTEX_TEXCOORD(ptr)			((const byte *)(ptr) + 48)
#define GL_VERTEX_COLOR(ptr)			((const byte *)(ptr) + 56)

typedef unsigned int		glIndex_t;

struct glVertex_t {
	glqVec3					xyz;
	glqVec3					normal;
	glqVec3					tangents[2];
	glqVec2					st;
	glqColor				color;
};

/*
 ==============================================================================

 TEXTURE MANAGER

 ==============================================================================
*/

#define MAX_TEXTURES					8192

enum textureType_t {
	TT_2D,
	TT_3D,
	TT_CUBE,
	TT_ARRAY
};

enum textureFlags_t {
	TF_INTERNAL				= BIT(0),
	TF_ALLOWCAPTURE			= BIT(1),
	TF_ALLOWUPDATE			= BIT(2),
	TF_NOPICMIP				= BIT(3),
	TF_UNCOMPRESSED			= BIT(4),
	TF_BUMP					= BIT(5),
	TF_DIFFUSE				= BIT(6),
	TF_SPECULAR				= BIT(7),
	TF_LIGHT				= BIT(8),
	TF_SHADOW				= BIT(9)
};

enum textureFormat_t {
	TF_LUMINANCE,
	TF_LUMINANCE_ALPHA,
	TF_RGB,
	TF_RGBA,
	TF_DEPTH_16,
	TF_DEPTH_24,
	TF_COMPRESSED_DXT1C,
	TF_COMPRESSED_DXT1A,
	TF_COMPRESSED_DXT3,
	TF_COMPRESSED_DXT5,
	TF_COMPRESSED_RXGB
};

enum textureFilter_t {
	TF_DEFAULT,
	TF_NEAREST,
	TF_LINEAR
};

enum textureWrap_t {
	TW_REPEAT,
	TW_REPEAT_MIRRORED,
	TW_CLAMP,
	TW_CLAMP_TO_ZERO,
	TW_CLAMP_TO_ZERO_ALPHA
};

struct texture_t {
	char					name[MAX_PATH_LENGTH];

	textureType_t			type;
	int						flags;
	textureFormat_t			format;
	textureFilter_t			filter;
	textureWrap_t			wrap;

	int						width;
	int						height;
	int						depth;
	int						size;
	uint					target;
	uint					internalFormat;
	int						lumpWidth;
	int						lumpHeight;
	byte *					offset;

	int						frameUsed;

	uint					textureId;

	texture_t *				nextHash;
};

texture_t *		R_FindTexture (const char *name, int flags, textureFilter_t filter, textureWrap_t wrap);
texture_t *		R_FindLumpTexture (const char *name, int flags, textureFilter_t filter, textureWrap_t wrap, int lumpWidth, int lumpHeight, byte *offset);
texture_t *		R_FindCubeTexture (const char *name, int flags, textureFilter_t filter, bool cameraSpace);

texture_t *		R_GetTextureByName (const char *name);
texture_t *		R_GetTextureByIndex (int index);

void			R_UploadTextureImage (texture_t *texture, int unit, const byte *image, int width, int height);
void			R_CopyFramebufferToTexture (texture_t *texture, int unit, int x, int y, int width, int height);

void			R_SetTextureSize (texture_t *texture);

void			R_ChangeTextureFilter ();
void			R_ChangeShadowTextureFilter ();

void			R_InitTextures ();
void			R_ShutdownTextures ();

/*
 ==============================================================================

 SHADER MANAGER

 ==============================================================================
*/

#define MAX_SHADERS						512

struct shader_t {
	char					name[MAX_PATH_LENGTH];

	uint					type;
	int						references;

	bool					compileStatus;

	uint					shaderId;

	shader_t *				nextHash;
};

shader_t *		R_FindShader (const char *name, uint type);

void			R_InitShaders ();
void			R_ShutdownShaders ();

/*
 ==============================================================================

 PROGRAM MANAGER

 ==============================================================================
*/

#define MAX_PROGRAMS					256
#define MAX_PROGRAM_UNIFORMS			64

#define MAX_UNIFORM_NAME_LENGTH			64

enum vertexAttrib_t {
	VA_NORMAL				= BIT(0),
	VA_TANGENT1				= BIT(1),
	VA_TANGENT2				= BIT(2),
	VA_TEXCOORD				= BIT(3),
	VA_COLOR				= BIT(4),
	VA_SCALE				= BIT(5),
};

enum uniformType_t {
	UT_VIEW_ORIGIN,
	UT_VIEW_AXIS,
	UT_ENTITY_ORIGIN,
	UT_ENTITY_AXIS,
	UT_SCREEN_MATRIX,
	UT_COORD_SCALE_AND_BIAS,
	UT_COLOR_SCALE_AND_BIAS,
	UT_CUSTOM
};

struct uniform_t {
	char					name[MAX_UNIFORM_NAME_LENGTH];

	uniformType_t			type;
	int						size;
	uint					format;
	int						location;

	int						unit;

	float					values[4];
};

struct program_t {
	char					name[MAX_PATH_LENGTH];

	shader_t *				vertexShader;
	shader_t *				fragmentShader;

	int						vertexAttribs;

	int						numUniforms;
	uniform_t *				uniforms;

	bool					linkStatus;

	uint					programId;

	program_t *				nextHash;
};

program_t *		R_FindProgram (const char *name, shader_t *vertexShader, shader_t *fragmentShader);

uniform_t *		R_GetProgramUniform (program_t *program, const char *name);
uniform_t *		R_GetProgramUniformExplicit (program_t *program, const char *name, int size, uint format);

void			R_SetProgramSampler (program_t *program, uniform_t *uniform, int unit);
void			R_SetProgramSamplerExplicit (program_t *program, const char *name, int size, uint format, int unit);

void			R_UniformFloat (uniform_t *uniform, float v0);
void			R_UniformFloat2 (uniform_t *uniform, float v0, float v1);
void			R_UniformFloat3 (uniform_t *uniform, float v0, float v1, float v2);
void			R_UniformFloat4 (uniform_t *uniform, float v0, float v1, float v2, float v3);
void			R_UniformFloatArray (uniform_t *uniform, int count, const float *v);

void			R_UniformVector2 (uniform_t *uniform, const glqVec2 &v);
void			R_UniformVector2Array (uniform_t *uniform, int count, const glqVec2 *v);

void			R_UniformVector3 (uniform_t *uniform, const glqVec3 &v);
void			R_UniformVector3Array (uniform_t *uniform, int count, const glqVec3 *v);

void			R_UniformVector4 (uniform_t *uniform, const glqVec4 &v);
void			R_UniformVector4Array (uniform_t *uniform, int count, const glqVec4 *v);

void			R_UniformMatrix3 (uniform_t *uniform, bool transpose, const glqMat3 &m);
void			R_UniformMatrix3Array (uniform_t *uniform, int count, bool transpose, const glqMat3 *m);
void			R_UniformMatrix3Identity (uniform_t *uniform);

void			R_UniformMatrix4 (uniform_t *uniform, bool transpose, const glqMat4 &m);
void			R_UniformMatrix4Array (uniform_t *uniform, int count, bool transpose, const glqMat4 *m);
void			R_UniformMatrix4Identity (uniform_t *uniform);

void			R_InitPrograms ();
void			R_ShutdownPrograms ();

/*
 ==============================================================================

 MATERIAL MANAGER

 ==============================================================================
*/

#define MAX_MATERIALS					4096
#define MAX_STAGES						32

#define MAX_EXPRESSION_OPS				512
#define MAX_EXPRESSION_REGISTERS		512

#define MAX_TEXMODS						4

#define MAX_SHADER_PARMS				32
#define MAX_SHADER_MAPS					16

enum materialType_t {
	MT_GENERIC,
	MT_LIGHT,
	MT_NOMIP
};

enum materialFlags_t {
	MF_EXPLICIT				= BIT(0),
	MF_DEFAULTED			= BIT(1),
	MF_FORCEOVERLAYS		= BIT(2),
	MF_NOOVERLAYS			= BIT(3),
	MF_FORCESHADOWS			= BIT(4),
	MF_NOSHADOWS			= BIT(5),
	MF_NOINTERACTIONS		= BIT(6),
	MF_NOAMBIENT			= BIT(7),
	MF_NOBLEND				= BIT(8),
	MF_NOFOG				= BIT(9),
	MF_UNSHADOWED			= BIT(10),
	MF_UPDATECURRENTCOLOR	= BIT(11),
	MF_NEEDCURRENTCOLOR		= BIT(12),
	MF_UPDATECURRENTDEPTH	= BIT(13),
	MF_NEEDCURRENTDEPTH		= BIT(14),
	MF_POLYGONOFFSET		= BIT(15),
	MF_LIGHTNING			= BIT(16)
};

enum materialCoverage_t {
	MC_OPAQUE,
	MC_PERFORATED,
	MC_TRANSLUCENT
};

enum surfaceParm_t {
	SURFACEPARM_NONE		= 0,
	SURFACEPARM_LIGHTING	= BIT(0),
	SURFACEPARM_SKY			= BIT(1),
	SURFACEPARM_WARP		= BIT(0),
};

enum sort_t {
	SORT_BAD,
	SORT_OPAQUE,
	SORT_DECAL,
	SORT_GLARE,
	SORT_REFRACTABLE,
	SORT_REFRACTIVE,
	SORT_FARTHEST,
	SORT_ALMOST_FARTHEST,
	SORT_FAR,
	SORT_MEDIUM,
	SORT_NEAR,
	SORT_ALMOST_NEAREST,
	SORT_NEAREST,
	SORT_POST_PROCESS
};

enum lightType_t {
	LT_GENERIC,
	LT_AMBIENT,
	LT_BLEND,
	LT_FOG
};

enum subviewType_t {
	ST_NONE,
	ST_MIRROR,
	ST_REMOTE
};

enum cullType_t {
	CT_FRONT_SIDED,
	CT_BACK_SIDED,
	CT_TWO_SIDED
};

enum deform_t {
	DFRM_NONE,
	DFRM_EXPAND,
	DFRM_MOVE,
	DFRM_SPRITE,
	DFRM_TUBE,
	DFRM_BEAM
};

enum stageLighting_t {
	SL_AMBIENT,
	SL_BUMP,
	SL_DIFFUSE,
	SL_SPECULAR
};

enum texGen_t {
	TG_EXPLICIT,
	TG_VECTOR,
	TG_NORMAL,
	TG_REFLECT,
	TG_SKYBOX,
	TG_WOBBLESKY,
	TG_SCREEN
};

enum texMod_t {
	TM_TRANSLATE,
	TM_SCALE,
	TM_CENTERSCALE,
	TM_SHEAR,
	TM_ROTATE
};

enum vertexColor_t {
	VC_IGNORE,
	VC_MODULATE,
	VC_INVERSE_MODULATE
};

enum drawState_t {
	DS_POLYGONOFFSET		= BIT(0),
	DS_BLEND				= BIT(1),
	DS_ALPHATEST			= BIT(2),
	DS_IGNOREALPHATEST		= BIT(3),
	DS_MASKRED				= BIT(4),
	DS_MASKGREEN			= BIT(5),
	DS_MASKBLUE				= BIT(6),
	DS_MASKALPHA			= BIT(7)
};

enum opType_t {
	OP_TYPE_MULTIPLY,
	OP_TYPE_DIVIDE,
	OP_TYPE_MOD,
	OP_TYPE_ADD,
	OP_TYPE_SUBTRACT,
	OP_TYPE_GREATER,
	OP_TYPE_LESS,
	OP_TYPE_GEQUAL,
	OP_TYPE_LEQUAL,
	OP_TYPE_EQUAL,
	OP_TYPE_NOTEQUAL,
	OP_TYPE_AND,
	OP_TYPE_OR,
	OP_TYPE_TABLE,
	OP_TYPE_SOUND
};

enum expRegister_t {
	EXP_REGISTER_CONSTANT_ONE,
	EXP_REGISTER_CONSTANT_ZERO,
	EXP_REGISTER_TIME,
	EXP_REGISTER_PARM0,
	EXP_REGISTER_PARM1,
	EXP_REGISTER_PARM2,
	EXP_REGISTER_PARM3,
	EXP_REGISTER_PARM4,
	EXP_REGISTER_PARM5,
	EXP_REGISTER_PARM6,
	EXP_REGISTER_PARM7,
	EXP_REGISTER_NUM_PREDEFINED
};

struct expOp_t {
	opType_t				type;

	int						a;
	int						b;
	int						c;
};

struct decalInfo_t {
	float					fadeInTime;
	float					stayTime;
	float					fadeOutTime;

	glqVec4					startRGBA;
	glqVec4					stayRGBA;
	glqVec4					endRGBA;
};

struct shaderParm_t {
	uniform_t *				uniform;

	int						registers[4];
};

struct shaderMap_t {
	uniform_t *				uniform;

	texture_t *				texture;

	cinHandle_t				cinematicHandle;
};

struct textureStage_t {
	int						flags;
	textureFilter_t			filter;
	textureWrap_t			wrap;

	texture_t *				texture;

	cinHandle_t				cinematicHandle;

	texGen_t				texGen;
	glqVec4					texGenVectors[2];
	int						texGenRegisters[3];

	int						numTexMods;
	texMod_t				texMods[MAX_TEXMODS];
	int						texModsRegisters[MAX_TEXMODS][2];
};

struct colorStage_t {
	bool					identity;

	float					scale;
	float					bias;

	int						registers[4];

	vertexColor_t			vertexColor;
};

struct shaderStage_t {
	program_t *				program;

	shader_t *				vertexShader;
	shader_t *				fragmentShader;

	float					colorScale;
	float					colorBias;

	int						numShaderParms;
	shaderParm_t			shaderParms[MAX_SHADER_PARMS];

	int						numShaderMaps;
	shaderMap_t				shaderMaps[MAX_SHADER_MAPS];
};

struct stage_t {
	stageLighting_t			lighting;

	int						conditionRegister;

	textureStage_t			textureStage;
	colorStage_t			colorStage;
	shaderStage_t			shaderStage;

	glqVec4					parms;

	int						drawState;

	float					polygonOffset;

	uint					blendSrc;
	uint					blendDst;
	uint					blendMode;

	int						alphaTestRegister;
};

struct material_t {
	char					name[MAX_PATH_LENGTH];
	int						index;

	materialType_t			type;
	int						flags;

	materialCoverage_t		coverage;

	surfaceParm_t			surfaceParm;

	int						conditionRegister;

	sort_t					sort;

	lightType_t				lightType;
	texture_t *				lightFalloffImage;
	texture_t *				lightCubeImage;

	int						spectrum;

	subviewType_t			subviewType;
	texture_t *				subviewTexture;
	int						subviewWidth;
	int						subviewHeight;

	cullType_t				cullType;

	float					polygonOffset;

	decalInfo_t				decalInfo;

	deform_t				deform;
	int						deformRegisters[3];

	int						numStages;
	int						numAmbientStages;
	stage_t *				stages;

	bool					constantExpressions;

	int						numOps;
	expOp_t *				expressionOps;

	int						numRegisters;
	float *					expressionRegisters;

	material_t *			nextHash;
};

material_t *	R_FindMaterial (const char *name, materialType_t type, surfaceParm_t surfaceParm);

void			R_EvaluateRegisters (material_t *material, float time, const float *parms, int soundEmitterHandle, float *registers);

void			R_InitMaterials ();
void			R_ShutdownMaterials ();

/*
 ==============================================================================

 SKIN MANAGER

 ==============================================================================
*/

#define MAX_SKINS						512

#define MAX_SKIN_MAPPINGS				32

struct skinMapping_t {
	material_t *			from;
	material_t *			to;
};

struct skin_t {
	char					name[MAX_PATH_LENGTH];

	int						numMappings;
	skinMapping_t *			mappings;

	skin_t *				nextHash;
};

skin_t *			R_FindSkin (const char *name);

material_t *		R_RemapMaterialBySkin (material_t *material, skin_t *skin);

void				R_InitSkins ();
void				R_ShutdownSkins ();

/*
 ==============================================================================

 FONT MANAGER

 ==============================================================================
*/

#define MAX_FONTS						32

struct font_t {
	char					name[MAX_PATH_LENGTH];
	bool					defaulted;

	fontSet_t *				fontSet;

	font_t *				nextHash;
};

font_t *			R_FindFont (const char *name);

void				R_InitFonts ();
void				R_ShutdownFonts ();

/*
 ==============================================================================

 FRAMEBUFFER MANAGER

 ==============================================================================
*/

#define MAX_FRAMEBUFFERS				32

struct renderbuffer_t {
	int						width;
	int						height;

	uint					format;
	int						size;

	uint					renderbufferId;
};

struct framebuffer_t {
	char					name[MAX_PATH_LENGTH];

	int						width;
	int						height;
	int						depth;

	glqRect					rect;

	texture_t *				colorTexture;
	texture_t *				depthTexture;

	renderbuffer_t			colorBuffer;
	renderbuffer_t			depthBuffer;
	renderbuffer_t			stencilBuffer;

	uint					framebufferId;
};

framebuffer_t *		R_CreateFramebuffer (const char *name, int width, int height, int depth);
void				R_ResizeFramebuffer (framebuffer_t *framebuffer, int width, int height, int depth);

void				R_AttachColorTextureToFramebuffer (framebuffer_t *framebuffer, texture_t *texture, int index, int colorIndex);
void				R_AttachDepthTextureToFramebuffer (framebuffer_t *framebuffer, texture_t *texture, int index);

void				R_AttachColorBufferToFramebuffer (framebuffer_t *framebuffer, uint format, int colorIndex);
void				R_AttachDepthBufferToFramebuffer (framebuffer_t *framebuffer, uint format);
void				R_AttachStencilBufferToFramebuffer (framebuffer_t *framebuffer, uint format);

void				R_CheckFramebufferStatus (framebuffer_t *framebuffer);

void				R_InitFramebuffers ();
void				R_ShutdownFramebuffers ();

/*
 ==============================================================================

 ARRAY BUFFER MANAGER

 ==============================================================================
*/

#define MAX_ARRAY_BUFFERS				4096

#define INDEX_OFFSET(ptr, offset)		((const byte *)(ptr) + ((offset) * sizeof(glIndex_t)))
#define VERTEX_OFFSET(ptr, offset)		((const byte *)(ptr) + ((offset) * sizeof(glVertex_t)))

struct arrayBuffer_t {
	char					name[MAX_PATH_LENGTH];

	bool					dynamic;
	int						count;

	int						size;
	uint					usage;
	bool					mapped;

	int						frameUsed;

	uint					bufferId;

	arrayBuffer_t *			next;
};

arrayBuffer_t *	R_AllocIndexBuffer (const char *name, bool dynamic, int indexCount, const glIndex_t *indexData);
void			R_ReallocIndexBuffer (arrayBuffer_t *indexBuffer, int indexCount, const glIndex_t *indexData);
void			R_FreeIndexBuffer (arrayBuffer_t *indexBuffer);
bool			R_UpdateIndexBuffer (arrayBuffer_t *indexBuffer, int indexOffset, int indexCount, const glIndex_t *indexData, bool discard, bool synchronize);
glIndex_t *		R_MapIndexBuffer (arrayBuffer_t *indexBuffer, int indexOffset, int indexCount, bool discard, bool synchronize);
bool			R_UnmapIndexBuffer (arrayBuffer_t *indexBuffer);

arrayBuffer_t *	R_AllocVertexBuffer (const char *name, bool dynamic, int vertexCount, const glVertex_t *vertexData);
void			R_ReallocVertexBuffer (arrayBuffer_t *vertexBuffer, int vertexCount, const glVertex_t *vertexData);
void			R_FreeVertexBuffer (arrayBuffer_t *vertexBuffer);
bool			R_UpdateVertexBuffer (arrayBuffer_t *vertexBuffer, int vertexOffset, int vertexCount, const glVertex_t *vertexData, bool discard, bool synchronize);
glVertex_t *	R_MapVertexBuffer (arrayBuffer_t *vertexBuffer, int vertexOffset, int vertexCount, bool discard, bool synchronize);
bool			R_UnmapVertexBuffer (arrayBuffer_t *vertexBuffer);

void			R_InitArrayBuffers ();
void			R_ShutdownArrayBuffers ();

/*
 ==============================================================================

 MODEL MANAGER

 ==============================================================================
*/

#define MAX_MODELS						2048

#define MIP_LEVELS						4

#define SURF_PLANEBACK					2

enum modelType_t {
	MODEL_BAD,
	MODEL_INLINE,
	MODEL_MDL,
	MODEL_MD3,
	MODEL_SPRITE
};

struct mipTexture_t {
	char					name[16];
	uint					width;
	uint					height;
	uint					offsets[MIP_LEVELS];
};

struct edge_t {
	ushort					v[2];
};

struct texInfo_t {
	int						flags;

	glqVec4					vecs[2];

	material_t *			material;

	int						width;
	int						height;

	bool					clamp;
};

struct triangle_t {
	glIndex_t				index[3];
};

struct surface_t {
	int						flags;

	int						firstEdge;
	int						numEdges;

	glqPlane *				plane;
	texInfo_t *				texInfo;

	glqBounds				bounds;

	int						numTriangles;
	triangle_t *			triangles;

	int						numVertices;
	glVertex_t *			vertices;

	arrayBuffer_t *			indexBuffer;		// Indices in write-only array buffer memory
	int						indexOffset;		// Offset into first surface index inside indexBuffer

	arrayBuffer_t *			vertexBuffer;		// Vertices in write-only array buffer memory
	int						vertexOffset;		// Offset into first surface vertex inside vertexBuffer

	int						viewCount;
	int						checkCount;
};

struct node_t {
	// Common with leaf
	int						contents;			// 0, to differentiate from leafs

	glqBounds				bounds;

	node_t *				parent;

	int						viewCount;
	int						visCount;

	// Node specific
	glqPlane *				plane;

	node_t *				children[2];

	ushort					firstSurface;
	ushort					numSurfaces;
};

struct leaf_t {
	// Common with node
	int						contents;			// Lesser than 0, to differentiate from nodes

	glqBounds				bounds;

	node_t *				parent;

	int						viewCount;
	int						visCount;

	// Leaf specific
	surface_t **			firstMarkSurface;
	int						numMarkSurfaces;

	byte *					compressedPVS;
};

struct inlineModel_t {
	glqVec3					origin;
	glqBounds				bounds;

	int						numSurfaces;
	surface_t *				surfaces;
};

struct world_t {
	char					name[MAX_PATH_LENGTH];
	int						size;

	int						numPlanes;
	glqPlane *				planes;

	int						numTextures;
	texture_t *				textures;

	int						numVertices;
	glVertex_t *			vertices;

	byte *					pvs;
	byte *					noPVS;

	int						numEdges;
	edge_t *				edges;

	int						numSurfEdges;
	int *					surfEdges;

	int						numTexInfo;
	texInfo_t *				texInfo;

	int						numSurfaces;
	surface_t *				surfaces;

	int						numMarkSurfaces;
	surface_t **			markSurfaces;

	int						numLeafs;
	leaf_t *				leafs;

	int						numNodes;
	node_t *				nodes;

	int						numInlineModels;
	inlineModel_t *			inlineModels;
};

struct aliasMdlFrame_t {
	glqBounds				bounds;
	glqSphere				sphere;
};

struct aliasMdlTag_t {
	char					name[MAX_PATH_LENGTH];
	glqVec3					origin;
	glqMat3					axis;
};

struct aliasMdlMaterial_t {
	material_t *			material;
};

struct aliasMdlTriangle_t {
	int						faceFront;
	glIndex_t				index[3];
};

struct aliasMdlSt_t {
	int						onSeam;
	glqVec2					st;
};

struct aliasMdlFacePlane_t {
	glqVec3					normal;
	float					dist;
};

struct aliasMdlVertex_t {
	glqVec3					xyz;
	glqVec3					normal;
	glqVec3					tangents[2];
};

struct aliasMdlSurface_t {
	int						numMaterials;
	aliasMdlMaterial_t *	materials;

	int						numTriangles;
	aliasMdlTriangle_t *	triangles;

	aliasMdlFacePlane_t *	facePlanes;

	int						numVertices;
	aliasMdlSt_t *			st;
	aliasMdlVertex_t *		vertices;

	arrayBuffer_t *			indexBuffer;		// Indices in write-only array buffer memory
	int						indexOffset;		// Offset into first surface index inside indexBuffer

	arrayBuffer_t *			vertexBuffer;		// Vertices in write-only array buffer memory
	int						vertexOffset;		// Offset into first surface vertex inside vertexBuffer
};

struct aliasMdl_t {
	int						numFrames;
	aliasMdlFrame_t *		frames;

	int						numTags;
	aliasMdlTag_t *			tags;

	int						numSurfaces;
	aliasMdlSurface_t *		surfaces;
};

struct sprMdl_t {
	int todo;
};

struct model_t {
	char					name[MAX_PATH_LENGTH];

	modelType_t				type;
	void *					data;
	int						size;

	model_t *				nextHash;
};

model_t *		R_FindModel (const char *name);

void			R_LoadInlineModel (int index, void *data);

void			R_InitModels ();
void			R_ShutdownModels ();

/*
 ==============================================================================

 IMAGE LOADING

 ==============================================================================
*/

bool			R_LoadImage (const char *name, int flags, textureWrap_t wrap, byte **image, int *width, int *height, textureFormat_t *format, bool *uncompressed, int lumpWidth, int lumpHeight, byte *offset);
bool			R_LoadCubeImages (const char *name, int flags, bool cameraSpace, byte **images, int *width, int *height, textureFormat_t *format, bool *uncompressed);
void			R_LoadLumpImage (byte **image, int width, int height, byte *offset, bool *uncompressed);

void			R_InitImages ();
void			R_ShutdownImages ();

/*
 ==============================================================================

 LIGHTS

 ==============================================================================
*/

#define NUM_SHADOW_BUFFERS				10

#define MAX_SHADOW_DISTANCE				8000.0f
#define MIN_SHADOW_DISTANCE				6000.0f

#define MAX_SHADOW_SPLITS				6

#define LIGHT_PLANEBITS					(BIT(6) - 1)

struct lightNode_t {
	node_t *				leaf;

	int						numSurfaces;
	surface_t **			surfaces;

	lightNode_t *			next;
};

struct lightData_t {
	bool					valid;
	bool					precached;

	material_t *			material;

	glqVec3					origin;
	glqVec3					direction;
	glqMat3					axis;

	glqVec3					corners[8];
	glqBounds				bounds;
	glqPlane				frustum[6];

	float					lightRange;

	glqPlane				fogPlane;

	glqVec2					shadowBiasScale;
	glqVec2					shadowJitterScale;

	glqMat4					projectionMatrix;
	glqMat4					modelviewMatrix;
	glqMat4					modelviewProjectionMatrix;

	lightNode_t *			nodes;
};

struct lightCache_t {
	renderLight_t			l;

	lightData_t				data;
};

bool			R_PrecachedLightData (scene_t *scene, const renderLight_t *renderLight, lightData_t *lightData);

void			R_SetupLightData (scene_t *scene, const renderLight_t *renderLight, lightData_t *lightData, bool inWorld);

int				R_LightCullBounds (lightData_t *lightData, const glqBounds &bounds, int planeBits);
int				R_LightCullLocalBounds (lightData_t *lightData, const glqBounds &bounds, const glqVec3 &origin, const glqMat3 &axis, int planeBits);

/*
 ==============================================================================

 DECALS

 ==============================================================================
*/

struct decal_t *	R_AllocDecal (scene_t *scene);
void				R_FreeDecal (scene_t *scene, struct decal_t *decal);

bool				R_UpdateDecal (scene_t *scene, struct decal_t *decal);

/*
 ==============================================================================

 SCENE MANAGER

 ==============================================================================
*/

#define MAX_RENDER_SCENES				16

#define MAX_RENDER_ENTITIES				4096
#define MAX_RENDER_LIGHTS				1024
#define MAX_RENDER_PARTICLES			8192
#define MAX_RENDER_DECALS				1024

struct entity_t {
	bool					active;
	int						index;

	renderEntity_t			e;

	int						viewCount;

	entity_t *				prev;
	entity_t *				next;
};

struct light_t {
	bool					active;
	int						index;

	renderLight_t			l;

	lightData_t				data;

	int						viewCount;

	light_t *				prev;
	light_t *				next;
};

struct particle_t {
	bool					active;
	int						index;

	renderParticle_t		p;

	particle_t *			prev;
	particle_t *			next;
};

struct decal_t {
	bool					active;
	int						index;

	int						startTime;
	int						endTime;

	glqVec3					origin;

	material_t *			material;

	entity_t *				parentEntity;		// Parent entity for culling
	surface_t *				parentSurface;		// Parent surface for culling

	model_t *				baseModel;
	int						baseSurface;
	int *					baseIndices;

	glqColor				fadeColor;

	int						numIndices;
	glIndex_t *				indices;

	int						numVertices;
	glVertex_t *			vertices;

	int						frameCount;

	decal_t *				prev;
	decal_t *				next;
};

struct scene_t {
	bool					primary;
	int						size;

	bool					inUse;
	bool					deferredFree;

	int						numEntities;
	int						maxEntities;
	entity_t *				entityList;

	int						numLights;
	int						maxLights;
	light_t *				lightList;

	int						numParticles;
	int						maxParticles;
	particle_t *			particleList;

	int						numDecals;
	int						maxDecals;
	decal_t *				decalList;

	// Active lists
	entity_t				activeEntity;
	light_t					activeLight;
	particle_t				activeParticle;
	decal_t					activeDecal;

	// Free lists
	entity_t *				freeEntity;
	light_t *				freeLight;
	particle_t *			freeParticle;
	decal_t *				freeDecal;

	// World entity for world rendering
	entity_t *				worldEntity;

	// Light cache
	lightCache_t *			lightCache[MAX_ENTITIES];
};

void			R_ClearScenes ();

void			R_InitScenes ();
void			R_ShutdownScenes ();

/*
 ==============================================================================

 POST-PROCESSING EFFECTS

 ==============================================================================
*/

#define MAX_POST_PROCESS_AREAS			512

struct postProcessParms_t {
	float					bloomContrast;
	float					bloomThreshold;
	float					baseIntensity;
	float					glowIntensity;

	glqVec3					colorShadows;
	glqVec3					colorHighlights;
	glqVec3					colorMidtones;
	glqVec3					colorMinOutput;
	glqVec3					colorMaxOutput;
	glqVec3					colorSaturation;
	glqVec3					colorTint;
	byte					colorTable[256][4];
	char					colorTableName[MAX_PATH_LENGTH];
};

struct postProcess_t {
	bool					editing;
	int						editingArea;

	postProcessParms_t		postProcessGeneric;

	char					postProcessName[MAX_PATH_LENGTH];
	postProcessParms_t		postProcessList[MAX_POST_PROCESS_AREAS];

	postProcessParms_t		postProcessParms;

	// Interpolation parameters
	int						time;

	postProcessParms_t		previous;
	postProcessParms_t *	current;
};

void				R_EditAreaPostProcess (int area);

void				R_UpdatePostProcess ();

void				R_InitPostProcess ();
void				R_ShutdownPostProcess ();

/*
 ==============================================================================

 POST-PROCESSING EFFECTS

 ==============================================================================
*/

void				R_InitPostProcess ();
void				R_ShutdownPostProcess ();

/*
 ==============================================================================

 GL STATE MANAGER

 ==============================================================================
*/


#define MAX_TEXTURE_UNITS				16

enum glVertexAttrib_t {
	GL_ATTRIB_NORMAL		= 2,
	GL_ATTRIB_TANGENT1		= 8,
	GL_ATTRIB_TANGENT2		= 9,
	GL_ATTRIB_TEXCOORD		= 10,
	GL_ATTRIB_COLOR			= 11
};

struct glState_t {
	bool					projectionMatrixIdentity;
	bool					modelviewMatrixIdentity;
	bool					textureMatrixIdentity[MAX_TEXTURE_UNITS];

	texture_t *				texture[MAX_TEXTURE_UNITS];
	program_t *				program;
	framebuffer_t *			framebuffer;
	arrayBuffer_t *			indexBuffer;
	arrayBuffer_t *			vertexBuffer;

	glqRect					viewport;
	glqRect					scissor;

	int						texUnit;
	uint					texTarget[MAX_TEXTURE_UNITS];

	int						texEnv[MAX_TEXTURE_UNITS];
	int						texGen[MAX_TEXTURE_UNITS][4];

	bool					cullFace;
	bool					polygonOffsetFill;
	bool					polygonOffsetLine;
	bool					blend;
	bool					alphaTest;
	bool					depthTest;
	bool					stencilTest;
	bool					textureGen[MAX_TEXTURE_UNITS][4];

	uint					cullMode;
	uint					polygonMode;
	float					polygonOffsetFactor;
	float					polygonOffsetUnits;
	uint					blendSrc;
	uint					blendDst;
	uint					blendMode;
	uint					alphaFunc;
	float					alphaFuncRef;
	uint					depthFunc;
	uint					stencilFunc[2];
	int						stencilFuncRef[2];
	uint					stencilFuncMask[2];
	uint					stencilOpFail[2];
	uint					stencilOpZFail[2];
	uint					stencilOpZPass[2];
	float					depthMin;
	float					depthMax;

	bool					colorMask[4];
	bool					depthMask;
	uint					stencilMask[2];
};

void			GL_LoadIdentity (uint mode);
void			GL_LoadMatrix (uint mode, const glqMat4 &matrix);
void			GL_LoadTransposeMatrix (uint mode, const glqMat4 &matrix);

void			GL_BindTexture (texture_t *texture);
void			GL_BindMultitexture (texture_t *texture, int unit);
void			GL_SelectTexture (int unit);
void			GL_EnableTexture (uint target);
void			GL_DisableTexture ();
void			GL_TexEnv (int texEnv);
void			GL_TexGen (uint texCoord, int texGen);

void			GL_BindProgram (program_t *program);

void			GL_BindFramebuffer (framebuffer_t *framebuffer);

void			GL_BindIndexBuffer (arrayBuffer_t *indexBuffer);
void			GL_BindVertexBuffer (arrayBuffer_t *vertexBuffer);

void			GL_Viewport (const glqRect &viewport);
void			GL_Scissor (const glqRect &scissor);

void			GL_Enable (uint cap);
void			GL_Disable (uint cap);
void			GL_CullFace (uint mode);
void			GL_PolygonMode (uint mode);
void			GL_PolygonOffset (float factor, float units);
void			GL_BlendFunc (uint src, uint dst);
void			GL_BlendEquation (uint mode);
void			GL_AlphaFunc (uint func, float ref);
void			GL_DepthFunc (uint func);
void			GL_StencilFunc (uint func, int ref, uint mask);
void			GL_StencilFuncSeparate (uint funcFront, uint funcBack, int refFront, int refBack, uint maskFront, uint maskBack);
void			GL_StencilOp (uint fail, uint zFail, uint zPass);
void			GL_StencilOpSeparate (uint failFront, uint failBack, uint zFailFront, uint zFailBack, uint zPassFront, uint zPassBack);
void			GL_DepthRange (float min, float max);
void			GL_ColorMask (bool red, bool green, bool blue, bool alpha);
void			GL_DepthMask (bool mask);
void			GL_StencilMask (uint mask);
void			GL_StencilMaskSeparate (uint maskFront, uint maskBack);

void			GL_Setup2DView (int time);
void			GL_Setup3DView (int time);

void			GL_SetDefaultState ();

void			GL_CheckForErrors ();

/*
 ==============================================================================

 DRAW SURFACES

 ==============================================================================
*/

#define MAX_DRAW_SURFACES				131072

#define DS_SHIFT_SORT					28
#define DS_SHIFT_ENTITY					16
#define DS_SHIFT_MATERIAL				4

typedef void				dsGeometry_t;

enum dsType_t {
	DS_SURFACE,
	DS_MODEL,
	DS_DECAL,
	DS_SPRITE,
	DS_BEAM,
	DS_PARTICLE,
	DS_NULL
};

struct drawSurface_t {
	dsType_t				type;
	dsGeometry_t *			geometry;

	entity_t *				entity;
	material_t *			material;

	const float *			registers;

	uint					sort;
	uint					bits;
};

void			R_SetupDrawSurfaces (int numDrawSurfaces, drawSurface_t **drawSurfaces);

void			R_AllocDrawSurfaces ();
void			R_GenerateDrawSurfaces ();

/*
 ==============================================================================

 DRAW LIGHTS

 ==============================================================================
*/

struct drawLight_t {
	light_t *				light;
	material_t *			material;

	const float *			registers;

	glqRect					scissor;

	int						shadowLOD;
	int						shadowFilter;

	int						shadowCubeBits;

	int						numShadowSplits;
	glqVec2					shadowSplitScales[MAX_SHADOW_SPLITS];
	glqVec2					shadowSplitBiases[MAX_SHADOW_SPLITS];

	bool					fogPlaneVisible;
	bool					lightShaftsVisible;

	int						numShadowSurfaces;
	drawSurface_t **		shadowSurfaces;

	int						numInteractionSurfaces;
	drawSurface_t **		interactionSurfaces;
};

void			R_AllocDrawLights ();
void			R_GenerateDrawLights ();

void			R_AllocLightSurfaces ();
void			R_GenerateLightSurfaces (drawLight_t *dl);

/*
 ==============================================================================

 FRONT-END

 ==============================================================================
*/

#define MAX_FRAME_MEMORY				(16 << 20)

#define MAX_RENDER_CROPS				8

#define MAX_POLYGON_POINTS				64

#define CULL_IN							0
#define CULL_OUT						-1

#define FAR_PLANE_DISTANCE				4000.0f

enum aspectRatio_t {
	ASPECT_NORMAL,
	ASPECT_WIDE,
	ASPECT_HIGH
};

enum frustum_t {
	FRUSTUM_LEFT,
	FRUSTUM_RIGHT,
	FRUSTUM_TOP,
	FRUSTUM_BOTTOM,
	FRUSTUM_NEAR,
	FRUSTUM_USER,
	NUM_FRUSTUM_PLANES
};

enum jitterTexture_t {
	JITTER_1,
	JITTER_4,
	JITTER_16,
	JITTER_64,
	NUM_JITTER_TEXTURES
};

enum interactionType_t {
	INTERACTION_GENERIC,
	NUM_INTERACTION_TYPES
};

enum ambientType_t {
	AMBIENT_GENERIC,
	NUM_AMBIENT_TYPES
};

enum blurFilter_t {
	BLUR_5X5,
	BLUR_9X9,
	BLUR_13X13,
	BLUR_17X17,
	NUM_BLUR_FILTERS
};

struct frameMemory_t {
	byte *					data;
	int						used;

	int						allocs;
	int						highwater;
};

struct viewParms_t {
	bool					primaryView;
	int						viewType;

	glqRect					viewport;
	glqRect					scissor;

	float					fovX;
	float					fovY;
	float					fovScale;

	float					zFar;

	float					floatTime;

	int						planeBits;

	glqPlane				frustum[NUM_FRUSTUM_PLANES];

	glqBounds				visBounds;

	glqMat4					projectionMatrix;
	glqMat4					modelviewMatrix;
	glqMat4					modelviewProjectionMatrix;

	int						numDrawSurfaces[4];
	drawSurface_t **		drawSurfaces[4];

	int						numDrawLights[4];
	drawLight_t **			drawLights[4];
};

struct subviewParms_t {
	int						viewType;

	entity_t *				entity;
	material_t *			material;

	glqBounds				ndcBounds;

	glqPlane				plane;

	glqVec3					origin;
	glqMat3					axis;

	float					fovX;
	float					fovY;
	float					fovScale;

	glqVec3					pvsOrigin;

	glqPlane				clipPlane;
};

struct projection2D_t {
	material_t *			material;

	const float *			registers;

	glqColor				color;
	float					parms[MAX_MATERIAL_PARMS];
};

struct renderCrop_t {
	int						width;
	int						height;

	glqRect					rect;

	float					xScale;
	float					yScale;

	aspectRatio_t			aspectRatio;
	float					aspectScale;
	float					aspectBias;
};

struct primaryView_t {
	scene_t *				scene;

	renderView_t			renderView;
};

struct performanceCounters_t {
	int						cullBoundsIn;
	int						cullBoundsClip;
	int						cullBoundsOut;
	int						cullSphereIn;
	int						cullSphereClip;
	int						cullSphereOut;
	int						cullLineIn;
	int						cullLineClip;
	int						cullLineOut;

	int						entityUpdates;
	int						lightUpdates;
	int						particleUpdates;

	int						entities;
	int						lights;
	int						particles;
	int						decals;

	int						leafs;

	int						surfaces;
	int						shadowSurfaces;
	int						interactionSurfaces;

	int						precachedShadows;
	int						precachedInteractions;

	int						staticLights;
	int						dynamicLights;

	int						dynamicIndices;
	int						dynamicVertices;
	int						dynamicSprite;
	int						dynamicBeam;

	int						deformIndices;
	int						deformVertices;
	int						deformExpand;
	int						deformMove;
	int						deformSprite;
	int						deformTube;
	int						deformBeam;

	int						views;
	int						draws;
	int						totalIndices;
	int						shadowIndices;
	int						interactionIndices;
	int						totalVertices;
	int						shadowVertices;
	int						interactionVertices;

	int						textures;
	int						textureBytes;

	int						renderTextures;
	int						renderTexturePixels;
	int						captureTextures;
	int						captureTexturePixels;
	int						updateTextures;
	int						updateTexturePixels;

	int						indexBuffers[2];
	int						indexBufferBytes[2];

	int						vertexBuffers[2];
	int						vertexBufferBytes[2];

	float					overdraw;
	float					overdrawLights;
};

struct reGlobals_t {
	int						time;
	float					floatTime;

	// Counters
	int						frameCount;
	int						viewCount;
	int						visCount;
	int						checkCount;

	int						viewArea;

	// View leaf;
	leaf_t *				viewLeaf;
	leaf_t *				oldViewLeaf;

	// Frame memory
	frameMemory_t			frameMemory;

	// Current scene
	scene_t *				scene;

	// Current render view
	renderView_t			renderView;

	// Current view/subview parms
	viewParms_t				viewParms;
	subviewParms_t			subviewParms;

	// Draw surfaces
	int						numDrawSurfaces[4];
	int						maxDrawSurfaces[4];
	int						firstDrawSurface[4];
	drawSurface_t **		drawSurfaces[4];

	// Draw lights
	int						numDrawLights[4];
	int						maxDrawLights[4];
	int						firstDrawLight[4];
	drawLight_t **			drawLights[4];

	// 2D drawing
	projection2D_t			projection2D;

	// Scenes
	scene_t *				scenes[MAX_RENDER_SCENES];

	// Render crops
	renderCrop_t			renderCrops[MAX_RENDER_CROPS];
	int						currentRenderCrop;

	// World map
	world_t *				world;

	// Post-processing effects
	postProcess_t			postProcess;

	// Environment shot rendering
	bool					envShotRendering;
	int						envShotSize;

	// Copy of the primary view needed by some functions
	bool					primaryViewAvailable;
	primaryView_t			primaryView;

	// Development tools
	texture_t *				testTexture;

	// Performance counters
	performanceCounters_t	pc;

	// Internal assets
	texture_t *				defaultTexture;
	texture_t *				whiteTexture;
	texture_t *				blackTexture;
	texture_t *				flatTexture;
	texture_t *				attenuationTexture;
	texture_t *				noAttenuationTexture;
	texture_t *				falloffTexture;
	texture_t *				noFalloffTexture;
	texture_t *				cubicFilterTexture;
	texture_t *				fogTexture;
	texture_t *				fogEnterTexture;
	texture_t *				noiseTexture;
	texture_t *				jitterTextures[NUM_JITTER_TEXTURES];
	texture_t *				colorTableTexture;
	texture_t *				cinematicTextures[MAX_CINEMATICS];
	texture_t *				mirrorTexture;
	texture_t *				remoteTexture;
	texture_t *				bloomTexture;
	texture_t *				scratchTexture;
	texture_t *				shadowTextures[NUM_SHADOW_BUFFERS];
	texture_t *				shadowCubeTextures[NUM_SHADOW_BUFFERS];
	texture_t *				shadowArrayTexture;
	texture_t *				lightShaftsTexture;
	texture_t *				currentColorTexture;
	texture_t *				currentDepthTexture;

	program_t *				interactionPrograms[NUM_INTERACTION_TYPES][4];
	program_t *				ambientLightPrograms[NUM_AMBIENT_TYPES];
	program_t *				blendLightProgram;
	program_t *				fogLightProgram;
	program_t *				lightShaftsPrograms[3];
	program_t *				blurPrograms[NUM_BLUR_FILTERS];
	program_t *				bloomProgram;
	program_t *				colorCorrectionProgram;

	material_t *			defaultMaterial;
	material_t *			defaultLightMaterial;
	material_t *			defaultProjectedLightMaterial;

	font_t *				defaultFont;

	// Tables
	byte					gammaTable[256];
};

extern reGlobals_t			rg;

extern glConfig_t			glConfig;

extern cvar_t *				r_logFile;
extern cvar_t *				r_ignoreGLErrors;
extern cvar_t *				r_clear;
extern cvar_t *				r_clearColor;
extern cvar_t *				r_frontBuffer;
extern cvar_t *				r_screenFraction;
extern cvar_t *				r_subviewOnly;
extern cvar_t *				r_lockVisibility;
extern cvar_t *				r_zNear;
extern cvar_t *				r_zFar;
extern cvar_t *				r_offsetFactor;
extern cvar_t *				r_offsetUnits;
extern cvar_t *				r_shadowOffsetFactor;
extern cvar_t *				r_shadowOffsetUnits;
extern cvar_t *				r_lightShaftsSampleStep;
extern cvar_t *				r_postProcessTime;
extern cvar_t *				r_forceImagePrograms;
extern cvar_t *				r_writeImagePrograms;
extern cvar_t *				r_colorMipLevels;
extern cvar_t *				r_maxDebugPolygons;
extern cvar_t *				r_maxDebugLines;
extern cvar_t *				r_maxDebugText;
extern cvar_t *				r_singleMaterial;
extern cvar_t *				r_singleEntity;
extern cvar_t *				r_singleLight;
extern cvar_t *				r_showFarClip;
extern cvar_t *				r_showCull;
extern cvar_t *				r_showUpdates;
extern cvar_t *				r_showScene;
extern cvar_t *				r_showSurfaces;
extern cvar_t *				r_showShadows;
extern cvar_t *				r_showInteractions;
extern cvar_t *				r_showLights;
extern cvar_t *				r_showDeforms;
extern cvar_t *				r_showPrimitives;
extern cvar_t *				r_showIndexBuffers;
extern cvar_t *				r_showVertexBuffers;
extern cvar_t *				r_showTextureUsage;
extern cvar_t *				r_showRenderToTexture;
extern cvar_t *				r_showMemory;
extern cvar_t *				r_showTextures;
extern cvar_t *				r_showDepth;
extern cvar_t *				r_showOverdraw;
extern cvar_t *				r_showLightCount;
extern cvar_t *				r_showLightVolumes;
extern cvar_t *				r_showLightScissors;
extern cvar_t *				r_showVertexColors;
extern cvar_t *				r_showTextureCoords;
extern cvar_t *				r_showTangentSpace;
extern cvar_t *				r_showLightShafts;
extern cvar_t *				r_showBloom;
extern cvar_t *				r_showTris;
extern cvar_t *				r_showNormals;
extern cvar_t *				r_showTextureVectors;
extern cvar_t *				r_showBatchSize;
extern cvar_t *				r_showModelBounds;
extern cvar_t *				r_showLeafBounds;
extern cvar_t *				r_skipVisibility;
extern cvar_t *				r_skipSuppress;
extern cvar_t *				r_skipCulling;
extern cvar_t *				r_skipFaceCulling;
extern cvar_t *				r_skipEntityCulling;
extern cvar_t *				r_skipLightCulling;
extern cvar_t *				r_skipScissors;
extern cvar_t *				r_skipLightScissors;
extern cvar_t *				r_skipUpdates;
extern cvar_t *				r_skipSorting;
extern cvar_t *				r_skipBatching;
extern cvar_t *				r_skipEntities;
extern cvar_t *				r_skipLights;
extern cvar_t *				r_skipLightCache;
extern cvar_t *				r_skipConstantExpressions;
extern cvar_t *				r_skipDeforms;
extern cvar_t *				r_skipAmbient;
extern cvar_t *				r_skipBump;
extern cvar_t *				r_skipDiffuse;
extern cvar_t *				r_skipSpecular;
extern cvar_t *				r_skipShadows;
extern cvar_t *				r_skipSoftShadows;
extern cvar_t *				r_skipInteractions;
extern cvar_t *				r_skipAmbientLights;
extern cvar_t *				r_skipBlendLights;
extern cvar_t *				r_skipFogLights;
extern cvar_t *				r_skipTranslucent;
extern cvar_t *				r_skipPostProcess;
extern cvar_t *				r_skipShaders;
extern cvar_t *				r_skipSubviews;
extern cvar_t *				r_skipVideos;
extern cvar_t *				r_skipCopyToTextures;
extern cvar_t *				r_skipDynamicTextures;
extern cvar_t *				r_skipDrawElements;
extern cvar_t *				r_skipRender;
extern cvar_t *				r_skipRenderContext;
extern cvar_t *				r_skipFrontEnd;
extern cvar_t *				r_skipBackEnd;
extern cvar_t *				r_glDriver;
extern cvar_t *				r_mode;
extern cvar_t *				r_fullscreen;
extern cvar_t *				r_customWidth;
extern cvar_t *				r_customHeight;
extern cvar_t *				r_displayRefresh;
extern cvar_t *				r_multiSamples;
extern cvar_t *				r_alphaToCoverage;
extern cvar_t *				r_swapInterval;
extern cvar_t *				r_finish;
extern cvar_t *				r_gamma;
extern cvar_t *				r_contrast;
extern cvar_t *				r_brightness;
extern cvar_t *				r_indexBuffers;
extern cvar_t *				r_vertexBuffers;
extern cvar_t *				r_shaderQuality;
extern cvar_t *				r_lightScale;
extern cvar_t *				r_lightDetailLevel;
extern cvar_t *				r_lightShafts;
extern cvar_t *				r_lightShaftsQuality;
extern cvar_t *				r_lightShaftsShadows;
extern cvar_t *				r_shadowQuality;
extern cvar_t *				r_shadowFilter;
extern cvar_t *				r_shadowLinearFilter;
extern cvar_t *				r_postProcess;
extern cvar_t *				r_bloom;
extern cvar_t *				r_seamlessCubeMaps;
extern cvar_t *				r_inGameVideos;
extern cvar_t *				r_precompressedImages;
extern cvar_t *				r_roundImagesDown;
extern cvar_t *				r_mipLevel;
extern cvar_t *				r_mipLevelBump;
extern cvar_t *				r_mipLevelDiffuse;
extern cvar_t *				r_mipLevelSpecular;
extern cvar_t *				r_maxTextureSize;
extern cvar_t *				r_compressTextures;
extern cvar_t *				r_compressNormalTextures;
extern cvar_t *				r_textureFilter;
extern cvar_t *				r_textureLODBias;
extern cvar_t *				r_textureAnisotropy;

void			R_AllocFrameMemory ();
void			R_ClearFrameMemory ();

void *			R_FrameAlloc (int size);
void *			R_ClearedFrameAlloc (int size);

bool			R_ClipPolygon (int numPoints, glqVec3 *points, const glqPlane &plane, float epsilon, int *numClipped, glqVec3 *clipped);

void			R_LocalPointToWorld (const glqVec3 &in, glqVec3 &out, const glqVec3 &origin, const glqMat3 &axis);

void			R_WorldPointToLocal (const glqVec3 &in, glqVec3 &out, const glqVec3 &origin, const glqMat3 &axis);
void			R_WorldVectorToLocal (const glqVec3 &in, glqVec3 &out, const glqMat3 &axis);
void			R_WorldAxisToLocal (const glqMat3 &in, glqMat3 &out, const glqMat3 &axis);

void			R_TransformWorldToDevice (const glqVec3 &world, glqVec3 &ndc, const glqMat4 &modelviewProjectionMatrix);
void			R_TransformDeviceToScreen (const glqVec3 &ndc, glqVec3 &screen, const glqRect &viewport);

void			R_AdjustHorzCoords (horzAdjust_t adjust, float percent, float xIn, float wIn, float *xOut, float *wOut);
void			R_AdjustVertCoords (vertAdjust_t adjust, float percent, float yIn, float hIn, float *yOut, float *hOut);

void			R_AdjustHorzCoordsInt (horzAdjust_t adjust, float percent, int xIn, int wIn, int *xOut, int *wOut);
void			R_AdjustVertCoordsInt (vertAdjust_t adjust, float percent, int yIn, int hIn, int *yOut, int *hOut);

int				R_CullBounds (const glqBounds &bounds, int planeBits);
int				R_CullLocalBounds (const glqBounds &bounds, const glqVec3 &origin, const glqMat3 &axis, int planeBits);
int				R_CullSphere (const glqSphere &sphere, int planeBits);
int				R_CullLocalSphere (const glqSphere &sphere, const glqVec3 &origin, const glqMat3 &axis, int planeBits);
int				R_CullLine (const glqVec3 &start, const glqVec3 &end, float epsilon, int planeBits);

void			R_MarkLeaves ();

void			R_SetFarClip ();

bool			R_AddSubviewSurface (dsType_t type, dsGeometry_t *geometry, entity_t *entity, material_t *material);

bool			R_RenderSubview ();

void			R_RenderView (bool primaryView, int viewType);

void			R_AddRenderViewCommand ();

void			R_SetGamma ();

bool			R_GetVideoModeInfo (int mode, int *width, int *height);

/*
 ==============================================================================

 BACK-END

 ==============================================================================
*/

#define MAX_COMMAND_BUFFER_SIZE			1048576

#define MAX_DRAWS						16384

#define MAX_INDICES						16384 * 3
#define MAX_VERTICES					8192

#define MAX_DYNAMIC_INDICES				(MAX_INDICES << 3)
#define MAX_DYNAMIC_VERTICES			(MAX_VERTICES << 3)

enum tmu_t {
	TMU_BUMP,
	TMU_DIFFUSE,
	TMU_SPECULAR,
	TMU_LIGHTPROJECTION,
	TMU_LIGHTFALLOFF,
	TMU_LIGHTCUBE,
	TMU_SHADOW,
	TMU_JITTER,
	TMU_DEPTH
};

enum ambientPass_t {
	AP_OPAQUE,
	AP_TRANSLUCENT,
	AP_POST_PROCESS
};

enum renderCommand_t {
	RC_RENDER_VIEW,
	RC_CAPTURE_RENDER,
	RC_UPDATE_TEXTURE,
	RC_DRAW_STRETCH_PIC,
	RC_DRAW_CINEMATIC,
	RC_CROP_SIZE,
	RC_SETUP_BUFFERS,
	RC_SWAP_BUFFERS,
	RC_END_OF_LIST
};

struct commandBuffer_t {
	byte *					data;
	int						used;
};

struct debugPolygon_t {
	int						allowInView;

	bool					fill;
	bool					depthTest;

	glqVec4					color;

	int						numPoints;
	glqVec3					points[MAX_POLYGON_POINTS >> 2];
};

struct debugLine_t {
	int						allowInView;

	bool					depthTest;

	glqVec4					color;

	glqVec3					start;
	glqVec3					end;
};

struct debugText_t {
	int						allowInView;

	bool					depthTest;

	glqVec4					color;
	bool					forceColor;

	glqVec3					origin;

	float					cw;
	float					ch;

	char					text[MAX_STRING_LENGTH];
};

struct renderViewParms_t {
	bool					primaryView;
	int						viewType;

	glqRect					viewport;
	glqRect					scissor;

	glqVec3					origin;
	glqMat3					axis;

	glqPlane				clipPlane;

	glqMat4					projectionMatrix;
	glqMat4					modelviewMatrix;
	glqMat4					modelviewProjectionMatrix;

	glqVec3					shadowDistanceFade;

	int						numDrawSurfaces[4];
	drawSurface_t **		drawSurfaces[4];

	int						numDrawLights[4];
	drawLight_t **			drawLights[4];
};

struct renderLocalParms_t {
	glqVec3					viewOrigin;
	glqMat3					viewAxis;
	glqMat4					viewMatrix;

	glqVec3					lightOrigin;
	glqVec3					lightDirection;
	glqMat3					lightAxis;
	glqVec4					lightPlane;
	glqMat4					lightMatrix;

	glqMat4					shadowMatrix;
	glqMat4					shadowMatrixArray[MAX_SHADOW_SPLITS];
};

struct renderViewCommand_t {
	renderCommand_t			commandId;

	int						time;

	scene_t *				scene;

	renderViewParms_t		viewParms;

	postProcessParms_t		postProcessParms;
};

struct captureRenderCommand_t {
	renderCommand_t			commandId;

	texture_t *				texture;
};

struct updateTextureCommand_t {
	renderCommand_t			commandId;

	texture_t *				texture;

	const byte *			image;
	int						width;
	int						height;
};

struct drawStretchPicCommand_t {
	renderCommand_t			commandId;

	material_t *			material;

	const float *			registers;

	float					x1;
	float					y1;
	float					x2;
	float					y2;
	float					x3;
	float					y3;
	float					x4;
	float					y4;

	float					s1;
	float					t1;
	float					s2;
	float					t2;

	glqColor				color;
};

struct drawCinematicCommand_t {
	renderCommand_t			commandId;

	texture_t *				texture;

	const byte *			image;
	bool					dirty;
	int						width;
	int						height;

	int						vx1;
	int						vy1;
	int						vx2;
	int						vy2;

	int						wx1;
	int						wy1;
	int						wx2;
	int						wy2;
};

struct cropSizeCommand_t {
	renderCommand_t			commandId;

	int						width;
	int						height;
};

struct setupBuffersCommand_t {
	renderCommand_t			commandId;
};

struct swapBuffersCommand_t {
	renderCommand_t			commandId;
};

struct interactionParms_t {
	uniform_t *				viewOrigin;
	uniform_t *				lightOrigin;
	uniform_t *				lightDirection;
	uniform_t *				lightAxis;
	uniform_t *				bumpMatrix;
	uniform_t *				diffuseMatrix;
	uniform_t *				specularMatrix;
	uniform_t *				lightMatrix;
	uniform_t *				shadowMatrix;
	uniform_t *				colorScaleAndBias;
	uniform_t *				diffuseColor;
	uniform_t *				specularColor;
	uniform_t *				specularParms;
	uniform_t *				lightColor;
	uniform_t *				lightPlane;
	uniform_t *				depthScaleAndBias;
	uniform_t *				shadowDistanceFade;
	uniform_t *				shadowSplitScales;
	uniform_t *				shadowParms;
	uniform_t *				jitterParms;
};

struct ambientLightParms_t {
	uniform_t *				viewOrigin;
	uniform_t *				bumpMatrix;
	uniform_t *				diffuseMatrix;
	uniform_t *				lightMatrix;
	uniform_t *				colorScaleAndBias;
	uniform_t *				diffuseColor;
	uniform_t *				parallaxParms;
	uniform_t *				lightColor;
};

struct blendLightParms_t {
	uniform_t *				lightMatrix;
	uniform_t *				lightColor;
};

struct fogLightParms_t {
	uniform_t *				lightMatrix;
	uniform_t *				lightColor;
};

struct lightShaftsParms_t {
	uniform_t *				viewOrigin;
	uniform_t *				lightOrigin;
	uniform_t *				lightAxis;
	uniform_t *				unprojectMatrix;
	uniform_t *				lightMatrix;
	uniform_t *				shadowMatrix;
	uniform_t *				lightColor;
	uniform_t *				lightPlane;
	uniform_t *				clipPlanes;
	uniform_t *				depthScaleAndBias;
	uniform_t *				lightShaftsParms;
};

struct bloomParms_t {
	uniform_t *				stOffset1;
	uniform_t *				stOffset2;
	uniform_t *				stOffset3;
	uniform_t *				bloomContrast;
	uniform_t *				bloomThreshold;
};

struct blurParms_t {
	uniform_t *				coordScale;
};

struct colorCorrectionParms_t {
	uniform_t *				baseIntensity;
	uniform_t *				glowIntensity;
	uniform_t *				colorShadows;
	uniform_t *				colorHighlights;
	uniform_t *				colorMidtones;
	uniform_t *				colorMinOutput;
	uniform_t *				colorMaxOutput;
	uniform_t *				colorSaturation;
	uniform_t *				colorTint;
};

struct shadowMap_t {
	bool					available;

	glqMat4					projectionMatrix;
	glqMat4					modelviewMatrix;
	glqMat4					modelviewProjectionMatrix;

	glqMat4					projectionMatrixArray[MAX_SHADOW_SPLITS];
	glqMat4					modelviewMatrixArray[MAX_SHADOW_SPLITS];
	glqMat4					modelviewProjectionMatrixArray[MAX_SHADOW_SPLITS];

	int						numSplits;
	glqVec2					splitScales[MAX_SHADOW_SPLITS];

	glqVec4					shadowParms;
	glqVec4					jitterParms;

	texture_t *				shadowTexture;
	texture_t *				jitterTexture;
};

struct drawInteraction_t {
	glqVec2					colorScaleAndBias;

	glqVec3					diffuseColor;
	glqVec3					specularColor;
	glqVec3					lightColor;

	glqVec2					specularParms;

	glqMat4					bumpMatrix;
	glqMat4					diffuseMatrix;
	glqMat4					specularMatrix;

	texture_t *				bumpTexture;
	texture_t *				diffuseTexture;
	texture_t *				specularTexture;
	texture_t *				lightProjectionTexture;
	texture_t *				lightFalloffTexture;
	texture_t *				lightCubeTexture;
};

struct backEnd_t {
	// General state
	bool					projection2D;

	int						time;
	float					floatTime;

	glqRect					viewport;
	glqRect					scissor;

	glqVec2					coordScale;
	glqVec2					coordBias;

	bool					depthFilling;
	bool					debugRendering;

	sort_t					currentColorCaptured;
	bool					currentDepthCaptured;

	bool					lightShaftsRendered;

	// Crop size
	int						cropWidth;
	int						cropHeight;

	// Render commands
	commandBuffer_t			commandBuffer;

	// Debug visualization
	int						numDebugPolygons;
	int						maxDebugPolygons;
	debugPolygon_t *		debugPolygons;

	int						numDebugLines;
	int						maxDebugLines;
	debugLine_t *			debugLines;

	int						numDebugText;
	int						maxDebugText;
	debugText_t *			debugText;

	// Program uniforms
	interactionParms_t		interactionParms[NUM_INTERACTION_TYPES][4];
	ambientLightParms_t		ambientLightParms[NUM_AMBIENT_TYPES];
	blendLightParms_t		blendLightParms;
	fogLightParms_t			fogLightParms;
	lightShaftsParms_t		lightShaftsParms[3];
	blurParms_t				blurParms[NUM_BLUR_FILTERS];
	bloomParms_t			bloomParms;
	colorCorrectionParms_t	colorCorrectionParms;

	// Shadow mapping
	shadowMap_t				shadowMap;

	framebuffer_t *			shadowBuffers[NUM_SHADOW_BUFFERS];
	framebuffer_t *			shadowCubeBuffers[NUM_SHADOW_BUFFERS];
	framebuffer_t *			shadowArrayBuffer;

	// Volumetric lighting
	framebuffer_t *			lightShaftsBuffer;

	// Scene
	scene_t *				scene;

	// View parms
	renderViewParms_t		viewParms;

	// Local parms
	renderLocalParms_t		localParms;

	// Light state
	light_t *				light;
	material_t *			lightMaterial;
	const float *			lightRegisters;

	// Batch state
	entity_t *				entity;
	material_t *			material;
	const float *			registers;

	bool					allowBatching;
	bool					allowFastPaths;

	int						numDraws;
	int *					drawIndexCount;
	const void **			drawIndexPointer;
	int *					drawBaseIndices;
	int *					drawBaseVertices;

	arrayBuffer_t *			indexBuffer;
	const void *			indexPointer;

	arrayBuffer_t *			vertexBuffer;
	const void *			vertexPointer;

	// Draw function for current batch
	void					(*drawBatch)();

	// Index and vertex arrays
	int						numIndices;
	glIndex_t *				indices;

	int						numVertices;
	glVertex_t *			vertices;

	// Dynamic index and vertex buffers
	int						dynamicIndexOffset;
	int						dynamicIndexNumber;
	arrayBuffer_t *			dynamicIndexBuffers[2];

	int						dynamicVertexOffset;
	int						dynamicVertexNumber;
	arrayBuffer_t *			dynamicVertexBuffers[2];
};

extern backEnd_t			backEnd;

// Geometry batching
void			RB_CheckOverflow (int numIndices, int numVertices);

void			RB_CreateBatch (entity_t *entity, material_t *material, const float *registers, void (*drawBatch)());
void			RB_RenderBatch ();

void			RB_BatchGeometry (dsType_t type, dsGeometry_t *geometry);

// Surface deforms
void			RB_Deform ();

// Material rendering setup
void			RB_Cull ();
void			RB_PolygonOffset ();
void			RB_DrawState (stage_t *stage);

void			RB_BindTexture (texture_t *texture, cinHandle_t cinematicHandle);
void			RB_BindMultitexture (texture_t *texture, cinHandle_t cinematicHandle, int unit);

void			RB_ComputeTexturePlanes (textureStage_t *textureStage, const float *registers, glqVec4 planes[4]);
void			RB_ComputeTextureMatrix (textureStage_t *textureStage, const float *registers, glqMat4 &matrix);

void			RB_SetupTextureStage (textureStage_t *textureStage);
void			RB_CleanupTextureStage (textureStage_t *textureStage);

void			RB_SetupColorStage (colorStage_t *colorStage);
void			RB_CleanupColorStage (colorStage_t *colorStage);

void			RB_SetupShaderStage (shaderStage_t *shaderStage);
void			RB_CleanupShaderStage (shaderStage_t *shaderStage);

// Rendering setup & utilities
void			RB_EntityState (entity_t *entity);
void			RB_EntityShadowState (entity_t *entity, light_t *light);

void			RB_TransformLightForEntity (light_t *light, entity_t *entity);

void			RB_ComputeLightMatrix (light_t *light, entity_t *entity, textureStage_t *textureStage);
void			RB_ComputeShadowMatrix (light_t *light, entity_t *entity);

void			RB_BindIndexBuffer ();
void			RB_BindVertexBuffer ();

void			RB_DrawElements ();
void			RB_DrawElementsWithCounters (int *totalIndices, int *totalVertices);
void			RB_DrawElementsStaticIndices (int numVertices, int numIndices, const void *indices);

// Common rendering
void			RB_FillDepthBuffer (int numDrawSurfaces, drawSurface_t **drawSurfaces);

void			RB_RenderMaterialPasses (int numDrawSurfaces, drawSurface_t **drawSurfaces, ambientPass_t pass);

void			RB_RenderLights (int numDrawLights, drawLight_t **drawLights);
void			RB_RenderBlendLights (int numDrawLights, drawLight_t **drawLights);
void			RB_RenderFogLights (int numDrawLights, drawLight_t **drawLights);

void			RB_AccumLightShafts (const glqRect &rect);
void			RB_RenderLightShafts ();

void			RB_PostProcess (const postProcessParms_t *postProcessParms);

void			RB_DrawMaterial2D ();

// Interaction rendering
void			RB_DrawSingleInteraction (drawInteraction_t *interaction);

// Debug tools rendering
void			RB_RenderDebugTools ();

// Main back-end interface.
// These should be the only functions ever called by the front-end.
void			RB_AddDebugPolygon (const glqVec4 &color, int numPoints, const glqVec3 *points, bool fill, bool depthTest, int allowInView);
void			RB_ClearDebugPolygons ();

void			RB_AddDebugLine (const glqVec4 &color, const glqVec3 &start, const glqVec3 &end, bool depthTest, int allowInView);
void			RB_ClearDebugLines ();

void			RB_AddDebugText (const glqVec4 &color, bool forceColor, const glqVec3 &origin, float cw, float ch, const char *text, bool depthTest, int allowInView);
void			RB_ClearDebugText ();

void			RB_ExecuteRenderCommands (const void *data);

void			RB_InitBackEnd ();
void			RB_ShutdownBackEnd ();

/*
 ==============================================================================

 IMPLEMENTATION SPECIFIC FUNCTIONS

 ==============================================================================
*/

#ifdef _WIN32

#define GL_DRIVER_OPENGL				"OpenGL32"

#define GLImp_SetDeviceGammaRamp		GLW_SetDeviceGammaRamp
#define GLImp_Activate					GLW_Activate
#define GLImp_ActivateContext			GLW_ActivateContext
#define GLImp_SwapBuffers				GLW_SwapBuffers
#define GLImp_Init						GLW_Init
#define GLImp_Shutdown					GLW_Shutdown

void			GLW_SetDeviceGammaRamp (const byte *gammaTable);
void			GLW_Activate (bool active);
void			GLW_ActivateContext (bool active);
void			GLW_SwapBuffers ();
void			GLW_Init ();
void			GLW_Shutdown ();

#else

#error "GLImp not available for this platform"

#endif


#endif	// __R_LOCAL_H__